package gecp.edge.image;

import gecp.math.Angle;

/**
 * Force
 *
 * @author Cosmin
 */
public class Force {

    /**
     * The force amplitude
     */
    protected double _amplitude;
    /**
     * The force angle
     */
    protected double _angle;
    /**
     * The movement of the force on x axis
     */
    protected double moveX;
    /**
     * The movement of the force on y axis
     */
    protected double moveY;

    /**
     * Constructing a force with an amplitude, a start point and an end point
     *
     * @param amplitude The force amplitude
     * @param x0 The first pixel coordinate on x axis
     * @param y0 The first pixel coordinate on y axis
     * @param x1 The second pixel coordinate on x axis
     * @param y1 The second pixel coordinate on y axis
     */
    public Force(double amplitude, int x0, int y0, int x1, int y1) {
        this._amplitude = amplitude;
        this._angle = Angle.computeAngle(x0, y0, x1, y1);
    }

    /**
     * Get the force amplitude
     *
     * @return The amplitude
     */
    public double getAmplitude() {
        return _amplitude;
    }

    /**
     * The angle for the force in degrees
     *
     * @return The angle
     */
    public double getAngleDegree() {
        return this._angle;
    }

    /**
     * The angle for the force in radians
     *
     * @return The angle
     */
    public double getAngleRadian() {
        return Math.toRadians(this._angle);
    }

    /**
     * Compute the movement in x axis and y axis of the force on all 4 quadrants
     */
    public void computeMovement() {
        this.moveX = this.getAmplitude() * Math.cos(this.getAngleRadian());
        this.moveY = this.getAmplitude() * Math.sin(this.getAngleRadian());
    }

    /**
     * Get the movement on x axis
     *
     * @return The move x
     */
    public double getMoveX() {
        return moveX;
    }

    /**
     * Get the movement on y axis
     *
     * @return The move x
     */
    public double getMoveY() {
        return moveY;
    }

    /**
     * Returns the change in the X direction represented by this force.
     */
    public double getXChange() {
        return getAmplitude() * Math.cos(getAngleRadian());
    }

    /**
     * Returns the change in the Y direction represented by this force.
     */
    public double getYChange() {
        return getAmplitude() * Math.sin(getAngleRadian());
    }

    /**
     * Set the angle and adjust it to 0 - 360
     *
     * @param a The angle value in degree
     */
    protected void setAngle(double a) {
        this._angle = Angle.affinityAngle(a);
    }

    /**
     * Set the amplitude
     *
     * @param amplitude The amplitude
     */
    public void setAmplitude(double amplitude) {
        this._amplitude = amplitude;
    }

    /**
     * Add another force to current force
     */
    public void sum(Force other) {
        double a1 = getAngleDegree();
        double a2 = other.getAngleDegree();
        double m1 = getAmplitude();
        double m2 = other.getAmplitude();
        double amplitude = Math.sqrt(m1 * m1 + m2 * m2 + 2 * m1 * m2 * Math.cos(Math.toRadians(a1 - a2)));
        double angle = Math.toDegrees(Math.asin(m2 * Math.sin(Math.toRadians(a2 - a1)) / amplitude)) + a1;
        if (!Double.isNaN(amplitude) && !Double.isNaN(angle)) {
            this.setAmplitude(amplitude);
            this.setAngle(angle);
        }
    }
}
